package callback

import (
	"database/sql"
	"log"
	"time"
	"xin-job/admin/dao"
	"xin-job/admin/dao/model"
	"xin-job/core/biz"
)

var instance = &CallbackHelper{}

func GetInstance() *CallbackHelper {
	return instance
}

type CallbackHelper struct {
	stopFlag chan struct{}
}

func (c *CallbackHelper) Start() {
	c.monitor()
}

func (c *CallbackHelper) Stop() {
	c.stopFlag <- struct{}{}
}

// monitor 监控
func (c *CallbackHelper) monitor() {
	go func() {
		defer func() {
			if err := recover(); err != nil {
				log.Printf("callback recover %v\n", err)
			}
		}()

		for {
			select {
			case <-c.stopFlag:
				// TODO 优雅停机
			default:
				date := time.Now().Add(-10 * time.Second)

				// 找到 10 分钟内，触发任务，但没有回调结果。
				// 且 注册表也没有数据
				// 的任务 id
				// 这种情况说明执行器已经掉线了。心跳都已经不维护了。
				ids := dao.FindLostJobIds(date)
				if len(ids) > 0 {
					for _, v := range ids {
						jobLog := &model.XxlJobLog{
							Id: v,
							HandleTime: sql.NullTime{
								Time:  time.Now(),
								Valid: true,
							},
							HandleCode: 500,
							HandleMsg:  "任务结果丢失，标记失败",
						}
						dao.UpdateHandleInfoAndFinish(jobLog)
					}
				}
			}

			time.Sleep(60 * time.Second)
		}

	}()
}

func (c *CallbackHelper) Callback(params []*biz.HandleCallbackParam) {
	go func() {
		defer func() {
			if err := recover(); err != nil {
				log.Printf("callback err %v\n", err)
			}
		}()

		for _, v := range params {
			c.callback0(v)
		}
	}()
}
func (c *CallbackHelper) callback0(param *biz.HandleCallbackParam) {
	jobLog := dao.LoadLog(param.LogId)

	if jobLog == nil {
		log.Printf("log item not found. %v\n", param.LogId)
		return
	}

	// 日志已经回调过一次
	if jobLog.HandleCode > 0 {
		log.Printf("log repeate callback. %v\n", param.LogId)
		return
	}

	var msg string
	if jobLog.HandleMsg != "" {
		msg = msg + jobLog.HandleMsg + "<br>"
	}

	if param.HandleMsg != "" {
		msg = msg + param.HandleMsg
	}

	jobLog.HandleTime = sql.NullTime{
		Time:  time.Now(),
		Valid: true,
	}
	jobLog.HandleCode = param.HandleCode
	jobLog.HandleMsg = msg

	dao.UpdateHandleInfoAndFinish(jobLog)
}
